﻿using System;
using System.Collections; 
using System.Collections.Generic;
using System.Text;
using Parseq.Util;
using Parseq.Core; 

namespace Parseq.Compiler
{
    /// <summary>
    /// walks through the captured IExps and transform them into the appropriate parser. 
    /// 
    /// the goal is to generate a TokenParser2 as in Builder as well as 
    /// </summary>
    class Compiler
    {
        public Compiler()
        {
            // the incoming is a list of exps. 
            // the output is a grammar parser. 
            // first we need to generate a symbol table to determine if things have appropriate definitions. 
            // how do we do that? 
            // if 
        }

        public BaseParser CompileExp (IExp exp) {
            if (exp is CharExp)
            {
                return this.CompileCharExp((CharExp)exp);
            }
            else if (exp is LiteralExp)
            {
                return this.CompileLiteralExp((LiteralExp)exp);
            }
            else if (exp is IDExp)
            {
                return this.CompileIDExp((IDExp)exp);
            }
            else if (exp is RepeatExp)
            {
                return this.CompileRepeatExp((RepeatExp)exp);
            }
            else if (exp is SequenceExp)
            {
                return this.CompileSequenceExp((SequenceExp)exp);
            }
            else if (exp is ChoiceExp)
            {
                return this.CompileChoiceExp((ChoiceExp)exp); 
            }
            else
            {
                throw new ArgumentException(string.Format("Unknown IExp: {0}", exp));
            }
        }

        public BaseParser CompileLiteralExp(LiteralExp exp) {
            return Combinator.Chars((string)exp.Inner);
        }

        public BaseParser CompileCharExp(CharExp exp)
        {
            return Combinator.CharEquals((char)exp.Inner); 
        }

        public BaseParser CompileRepeatExp(RepeatExp exp)
        {
            return Combinator.Repeat(this.CompileExp((IExp)exp.Inner), exp.Min, exp.Max); 
        }

        public BaseParser CompileSequenceExp(SequenceExp exp)
        {
            return Combinator.MakeSequence(Array.ConvertAll<IExp, BaseParser>((IExp[])exp.Inner, delegate(IExp exp2) { return this.CompileExp(exp2); }));
        }

        public BaseParser CompileChoiceExp(ChoiceExp exp)
        {
            return Combinator.MakeChoice(Array.ConvertAll<IExp, BaseParser>((IExp[])exp.Inner, delegate(IExp exp2) { return this.CompileExp(exp2); }));
        }

        public BaseParser CompileIDExp(IDExp exp)
        {
            // we'll need to reference the underlying object to return... it's possible that the object is not yet well defined... 
            // each token is basically a sequence parser. 
            // so the first pass is to generate the symbol tables based on the parse. 
            return Combinator.Chars((string)exp.Inner);
        }

    }
}
